package org.ahead4.joint.utils;

import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Map;

/**
 * RSA格式转换工具类
 * */
public class RSAKeyConvertUtils {

	public static void main(String[] args) {
		Map<String, String> map = RSAUtils.genKeyPair();
		String publicKeyString =  map.get(RSAUtils.PUBLIC_KEY);
		String privateKeyString = map.get(RSAUtils.PRIVATE_KEY);


		System.out.println(publicKeyString);
		System.out.println(privateKeyString);
	}

//	/**
//	 * 获取密钥对
//	 * 
//	 * @return
//	 * @throws NoSuchAlgorithmException
//	 */
//	public static HashMap<String, Object> getKeys()
//			throws NoSuchAlgorithmException {
//		HashMap<String, Object> map = new HashMap<String, Object>();
//		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
//		keyPairGen.initialize(1024);
//		KeyPair keyPair = keyPairGen.generateKeyPair();
//		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
//		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//		map.put("PUBLIC", publicKey);
//		map.put("PRIVATE", privateKey);
//		return map;
//	}

	/**
	 * 私钥转换成C#格式
	 * 
	 * @param encodedPrivateKey
	 * @return
	 */
	private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivateKey) {
		try {
			StringBuilder buff = new StringBuilder(1024);

			PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
					encodedPrivateKey);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
					.generatePrivate(pvkKeySpec);

			buff.append("<RSAKeyValue>");
			buff.append("<Modulus>").append(encodeBase64(removeMSZero(pvkKey.getModulus()
					.toByteArray()))).append("</Modulus>");

			buff.append("<Exponent>").append(encodeBase64(removeMSZero(pvkKey.getPublicExponent()
					.toByteArray()))).append("</Exponent>");

			buff.append("<P>").append(encodeBase64(removeMSZero(pvkKey.getPrimeP()
					.toByteArray()))).append("</P>");

			buff.append("<Q>").append(encodeBase64(removeMSZero(pvkKey.getPrimeQ()
					.toByteArray()))).append("</Q>");

			buff.append("<DP>").append(encodeBase64(removeMSZero(pvkKey.getPrimeExponentP()
					.toByteArray()))).append("</DP>");

			buff.append("<DQ>").append(encodeBase64(removeMSZero(pvkKey.getPrimeExponentQ()
					.toByteArray()))).append("</DQ>");

			buff.append("<InverseQ>").append(encodeBase64(removeMSZero(pvkKey.getCrtCoefficient()
					.toByteArray()))).append("</InverseQ>");

			buff.append("<D>").append(encodeBase64(removeMSZero(pvkKey.getPrivateExponent()
					.toByteArray()))).append("</D>");
			buff.append("</RSAKeyValue>");

			return buff.toString();
		} catch (Exception e) {
			System.err.println();
			return null;
		}
	}

	/**
	 * 公钥转成C#格式
	 * 
	 * @param encodedPublicKey
	 * @return
	 */
	private static String getRSAPublicKeyAsNetFormat(byte[] encodedPublicKey) {
		try {
			StringBuilder buff = new StringBuilder(1024);

			// Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA
			// public keys
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPublicKey pukKey = (RSAPublicKey) keyFactory
					.generatePublic(new X509EncodedKeySpec(encodedPublicKey));

			buff.append("<RSAKeyValue>");
			buff.append("<Modulus>").append(encodeBase64(removeMSZero(pukKey.getModulus().toByteArray()))).append("</Modulus>");
			buff.append("<Exponent>").append(encodeBase64(removeMSZero(pukKey.getPublicExponent().toByteArray()))).append("</Exponent>");
			buff.append("</RSAKeyValue>");
			return buff.toString();
		} catch (Exception e) {
			System.err.println();
			return null;
		}
	}

	/**
	 * 公钥转换成C#格式
	 * 
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String encodePublicKeyToXml(PublicKey key) throws Exception {
		if (!(key instanceof RSAPublicKey)) {
			return null;
		}
		RSAPublicKey pubKey = (RSAPublicKey) key;

		return "<RSAKeyValue>" +
				"<Modulus>" +
				encodeBase64(removeMSZero(pubKey.getModulus().toByteArray())) +
				"</Modulus>" +
				"<Exponent>" +
				encodeBase64(removeMSZero(pubKey.getPublicExponent()
						.toByteArray())) +
				"</Exponent>" +
				"</RSAKeyValue>";
	}

	/**
	 * @param data
	 * @return
	 */
	private static byte[] removeMSZero(byte[] data) {
		byte[] data1;
		int len = data.length;
		if (data[0] == 0) {
			data1 = new byte[data.length - 1];
			System.arraycopy(data, 1, data1, 0, len - 1);
		} else
			data1 = data;

		return data1;
	}

	/**
	 * base64编码
	 * 
	 * @param input
	 * @return
	 * @throws Exception
	 */
	public static String encodeBase64(byte[] input) throws Exception {
		Class<?> clazz = Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
		Method mainMethod = clazz.getMethod("encode", byte[].class);
		mainMethod.setAccessible(true);
		Object retObj = mainMethod.invoke(null, new Object[] { input });
		return (String) retObj;
	}

	/**
	 * base64解码
	 * 
	 * @param input
	 * @return
	 * @throws Exception
	 */
	public static byte[] decodeBase64(String input) throws Exception {
		Class<?> clazz = Class
				.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
		Method mainMethod = clazz.getMethod("decode", String.class);
		mainMethod.setAccessible(true);
		Object retObj = mainMethod.invoke(null, input);
		return (byte[]) retObj;
	}

	public static String byteToString(byte[] b) {
		return new String(b, StandardCharsets.UTF_8);
	}
}
